home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint108s.zoo / bios.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-27  |  21.4 KB  |  952 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * BIOS replacement routines
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "xbra.h"
  13.  
  14. #define UNDEF 0        /* should match definition in tty.c */
  15.  
  16. /* some key definitions */
  17. #define CTRLALT 0xc
  18. #define DEL 0x53    /* scan code of delete key */
  19. #define UNDO 0x61    /* scan code of undo key */
  20.  
  21. /* BIOS device definitions */
  22. #define CONSDEV 2
  23. #define AUXDEV 1
  24. #define PRNDEV 0
  25.  
  26. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  27. #define MAX_BHANDLE    4
  28.  
  29. /* BIOS redirection maps */
  30. const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  31. const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  32.  
  33. /* tty structures for the BIOS devices -- see biosfs.c */
  34. extern struct tty con_tty, aux_tty, midi_tty;
  35.  
  36. extern int tosvers;    /* from main.c */
  37.  
  38. char *kbshft;        /* set in main.c */
  39.  
  40. /* some BIOS vectors; note that the routines at these vectors may do nasty
  41.  * things to registers!
  42.  */
  43.  
  44. #define RWABS *((long *)0x476L)
  45. #define MEDIACH *((long *)0x47eL)
  46. #define GETBPB *((long *)0x472L)
  47.  
  48.  
  49. #if 1
  50. /* these are supposed to be tables holding the addresses of the
  51.  * first 8 BconXXX functions, but in fact only the first 5 are
  52.  * placed here (and device 5 only has Bconout implemented; 
  53.  * we don't use that device (raw console) anyway).
  54.  */
  55.  
  56. #define xconstat ((long *)0x51eL)
  57. #define xconin     ((long *)0x53eL)
  58. #define xcostat ((long *)0x55eL)
  59. #define xconout    ((long *)0x57eL)
  60.  
  61. #define BCOSTAT(dev) \
  62.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  63.        (int)callout1(xcostat[dev], dev) : Bcostat(dev))
  64. #define BCONOUT(dev, c) \
  65.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  66.        callout2(xconout[dev], dev, c) : Bconout(dev, c))
  67. #define BCONSTAT(dev) \
  68.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  69.        (int)callout1(xconstat[dev], dev) : Bconstat(dev))
  70. #define BCONIN(dev) \
  71.     ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
  72.        callout1(xconin[dev], dev) : Bconin(dev))
  73. #else
  74. #define BCOSTAT(dev) Bcostat(dev)
  75. #define BCONOUT(dev,c) Bconout(dev,c)
  76. #define BCONSTAT(dev) Bconstat(dev)
  77. #define BCONIN(dev) Bconin(dev)
  78. #endif
  79.  
  80. /* variables for monitoring the keyboard */
  81. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  82. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  83.  
  84. /* Getmpb is not allowed under MiNT */
  85.  
  86. long ARGS_ON_STACK
  87. getmpb(ptr)
  88.     void *ptr;
  89. {
  90.     UNUSED(ptr);
  91.  
  92.     DEBUG(("failed call to Getmpb"));
  93.     return -1;
  94. }
  95.  
  96.  
  97. /*
  98.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  99.  * to get the physical devices, go through u:\dev\
  100.  *
  101.  * A note on translation: all of the bco[n]XXX functions have a "u"
  102.  * variant that is actually what the user calls. For example,
  103.  * ubconstat is the function that gets control after the user does
  104.  * a Bconstat. It figures out what device or file handle is
  105.  * appropriate. Typically, it will be a biosfs file handle; a
  106.  * request is sent to biosfs, and biosfs in turn figures out
  107.  * the "real" device and calls bconstat.
  108.  */
  109.  
  110. /*
  111.  * WARNING: syscall.spp assumes that ubconstat never blocks.
  112.  */
  113. long ARGS_ON_STACK
  114. ubconstat(dev)
  115. int dev;
  116. {
  117.     if (dev < MAX_BHANDLE) {
  118.         FILEPTR *f = curproc->handle[binput[dev]];
  119.         return file_instat(f) ? -1 : 0;
  120.     }
  121.     else
  122.         return bconstat(dev);
  123. }
  124.  
  125. long
  126. bconstat(dev)
  127. int dev;
  128. {
  129.     if (dev == CONSDEV) {
  130.         if (checkkeys()) return 0;
  131.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  132.     }
  133.     if (dev == AUXDEV && has_bconmap)
  134.         dev = curproc->bconmap;
  135.  
  136.     return BCONSTAT(dev);
  137. }
  138.  
  139. /* bconin: input a character */
  140. /*
  141.  * WARNING: syscall.spp assumes that ubconin never
  142.  * blocks if ubconstat returns non-zero.
  143.  */
  144. long ARGS_ON_STACK
  145. ubconin(dev)
  146. int dev;
  147. {
  148.     if (dev < MAX_BHANDLE) {
  149.         FILEPTR *f = curproc->handle[binput[dev]];
  150.         return file_getchar(f, RAW);
  151.     }
  152.     else
  153.         return bconin(dev);
  154. }
  155.  
  156. long
  157. bconin(dev)
  158. int dev;
  159. {
  160.     IOREC_T *k;
  161.     long r;
  162.     short h;
  163.  
  164.     if (dev == CONSDEV) {
  165.         k = keyrec;
  166. again:
  167.         while (k->tail == k->head) {
  168.             yield();
  169.         }
  170.  
  171.         if (checkkeys()) goto again;
  172.  
  173.         h = k->head + 4;
  174.         if (h >= k->buflen)
  175.             h = 0;
  176.         r = *((long *)(k->bufaddr + h));
  177.         k->head = h;
  178.         return r;
  179.     }
  180.     else {
  181.         if (dev == AUXDEV && has_bconmap)
  182.             dev = curproc->bconmap;
  183.  
  184.         if (dev > 0) {
  185.             while (!BCONSTAT(dev)) {
  186.                 yield();
  187.             }
  188.         }
  189.     }
  190.  
  191.     r = BCONIN(dev);
  192.  
  193.     return r;
  194. }
  195.  
  196. /* bconout: output a character.
  197.  * returns 0 for failure, nonzero for success
  198.  */
  199.  
  200. long ARGS_ON_STACK
  201. ubconout(dev, c)
  202. int dev, c;
  203. {
  204.     FILEPTR *f;
  205.     char outp;
  206.  
  207.     if (dev < MAX_BHANDLE) {
  208.         f = curproc->handle[boutput[dev]];
  209.         if (!f) return 0;
  210.         if (is_terminal(f)) {
  211.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  212.         }
  213.         outp = c;
  214.         return (*f->dev->write)(f, &outp, 1L);
  215.     }
  216.     else if (dev == 5) {
  217.         c &= 0x00ff;
  218.         f = curproc->handle[-1];
  219.         if (!f) return 0;
  220.         if (is_terminal(f)) {
  221.             if (c < ' ') {
  222.             /* MW hack for quoted characters */
  223.                 tty_putchar(f, (long)'\033', RAW);
  224.                 tty_putchar(f, (long)'Q', RAW);
  225.             }
  226.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  227.         }
  228.     /* note: we're assuming sizeof(int) == 2 here! */
  229.         outp = c;
  230.         return (*f->dev->write)(f, &outp, 1L);
  231.     } else
  232.         return bconout(dev, c);
  233. }
  234.  
  235. long
  236. bconout(dev, c)
  237. int dev,c;
  238. {
  239.     int statdev;
  240.     long endtime;
  241. #define curtime *((unsigned long *)0x4baL)
  242.  
  243.     if (dev == AUXDEV && has_bconmap) {
  244.         dev = curproc->bconmap;
  245.     }
  246.  
  247. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  248.     if (dev == 3) {        /* MIDI */
  249.         statdev = 4;
  250.     } else if (dev == 4) {
  251.         statdev = 3;
  252.     } else {
  253.         statdev = dev;
  254.     }
  255.  
  256. /* provide a 10 second time out for the printer */
  257.     if (!BCOSTAT(statdev)) {
  258.         if (dev != PRNDEV) {
  259.             do {
  260.     /* BUG: Speedo GDOS isn't re-entrant; so printer output to the
  261.      * serial port could cause problems
  262.      */
  263.                 yield();
  264.             } while (!BCOSTAT(statdev));
  265.         } else {
  266.             endtime = curtime + 10*200L;
  267.             do {
  268. #if 0
  269.     /* Speedo GDOS isn't re-entrant, so we can't give up CPU
  270.      * time here :-(
  271.      */
  272.                 yield();
  273. #endif
  274.             } while (!BCOSTAT(statdev) && curtime < endtime);
  275.             if ( curtime >= endtime) return 0;
  276.         }
  277.     }
  278.  
  279. /* special case: many text accelerators return a bad value from
  280.  * Bconout, so we ignore the returned value for the console
  281.  * Sigh. serptch2 and hsmodem1 also screw this up, so for now let's
  282.  * only count on it being correct for the printer.
  283.  */
  284.     if (dev == PRNDEV) {
  285. /* NOTE: if your compiler complains about the next line, then Bconout is
  286.  * improperly declared in your osbind.h header file. it should be returning
  287.  * a long value; some libraries incorrectly have Bconout returning void
  288.  * (or cast the returned value to void)
  289.  */
  290.         return BCONOUT(dev,c);
  291.     } else {
  292.         (void)BCONOUT(dev, c);
  293.         return 1;
  294.     }
  295. }
  296.  
  297. /* rwabs: various disk stuff */
  298.  
  299. /* BUG: Rwabs should respect Dlock */
  300.  
  301. long ARGS_ON_STACK
  302. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  303. int rwflag, number, recno, dev;
  304. void *buffer;
  305. long lrecno;
  306. {
  307.     long r;
  308.     extern PROC *dlockproc[];    /* in dosdir.c */
  309.  
  310.     if (dev >= 0 && dev < NUM_DRIVES && dlockproc[dev]) {
  311.         if (dlockproc[dev] != curproc) {
  312.             DEBUG(("Rwabs: device %c is locked", dev+'A'));
  313.             return ELOCKED;
  314.         }
  315.     }
  316.  
  317. /* Note that some (most?) Rwabs device drivers don't bother saving
  318.  * registers, whereas our compiler expects politeness. So we go
  319.  * via callout(), which will save registers for us.
  320.  */
  321.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  322.     return r;
  323. }
  324.  
  325. /* setexc: set exception vector */
  326.  
  327. long ARGS_ON_STACK
  328. setexc(number, vector)
  329. int number;
  330. long vector;
  331. {
  332.     long *place;
  333.     long old;
  334.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  335.     extern int no_mem_prot;                /* in main.c */
  336.  
  337.     place = (long *)(((long)number) << 2);
  338.     if (number == 0x21)                /* trap_1 */
  339.         old = save_dos;
  340.     else if (number == 0x2d)            /* trap_13 */
  341.         old = save_bios;
  342.     else if (number == 0x2e)            /* trap_14 */
  343.         old = save_xbios;
  344.     else if (number == 0x101)
  345.         old = (long)curproc->criticerr;        /* critical error vector */
  346.     else if (number == 0x102)
  347.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  348.     else
  349.         old = *place;
  350.  
  351.     if (vector > 0) {
  352.     /* validate vector; this will cause a bus error if mem
  353.      * protection is on and the current process doesn't have
  354.      * access to the memory
  355.      */
  356.         if (*((long *)vector) == 0xDEADBEEFL)
  357.             return old;
  358.  
  359.         if (number == 0x21)
  360.             save_dos = vector;
  361.         else if (number == 0x2d)
  362.             save_bios = vector;
  363.         else if (number == 0x2e)
  364.             save_xbios = vector;
  365.         else if (number == 0x102)
  366.             curproc->ctxt[SYSCALL].term_vec = vector;
  367.         else if (number == 0x101) {
  368.             long mintcerr;
  369.  
  370.         /*
  371.          * problem: lots of TSR's look for the Setexc(0x101,...)
  372.           * that the AES does at startup time; so we have
  373.          * to pass it along.
  374.          */
  375.             mintcerr = (long) Setexc(0x101, (void *)vector);
  376.             curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
  377.             *place = mintcerr;
  378.         }
  379.         else {
  380.             if (!no_mem_prot) {
  381.             /*
  382.              * if memory protection is on, the vector should be
  383.              * pointing at supervisor or global memory
  384.              */
  385.                 MEMREGION *r;
  386.  
  387.                 r = addr2region(vector);
  388.                 if (r && get_prot_mode(r) == PROT_P) {
  389.                 DEBUG(("Changing protection to Supervisor because of Setexc"));
  390.                 mark_region(r, PROT_S);
  391.                 }
  392.             }
  393.         /* We would do just *place = vector except that
  394.          * someone else might be intercepting Setexc looking
  395.          * for something in particular...
  396.          */
  397.             old = (long) Setexc(number, (void *)vector);
  398.         }
  399.     }
  400.  
  401.     TRACE(("Setexc %d, %lx -> %lx", number, vector, old));
  402.     return old;
  403. }
  404.  
  405. /* tickcal: return milliseconds per system clock tick */
  406.  
  407. long ARGS_ON_STACK
  408. tickcal()
  409. {
  410.     return (long) (*( (unsigned *) 0x0442L ));
  411. }
  412.  
  413. /* getbpb: get BIOS parameter block */
  414.  
  415. long ARGS_ON_STACK
  416. getbpb(dev)
  417. int dev;
  418. {
  419.     long r;
  420.  
  421. /* we can't trust the Getbpb routine to accurately save all registers,
  422.  * so we do it ourselves
  423.  */
  424.     r = callout1(GETBPB, dev);
  425. /* 
  426.  * There is a bug in the  TOS  disk handling routines (well several actually).
  427.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  428.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  429.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  430.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  431.  * look a bit weird but that's better than killing the drive .
  432.  */
  433.     if (r) {
  434.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  435.             ((short *)r)[3] = 1;
  436.     }
  437.     return r;
  438. }
  439.  
  440. /* bcostat: return output device status */
  441.  
  442. /* WARNING: syscall.spp assumes that ubcostat never
  443.  * blocks
  444.  */
  445. long ARGS_ON_STACK
  446. ubcostat(dev)
  447. int dev;
  448. {
  449.     FILEPTR *f;
  450.  
  451. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  452.     if (dev == 4) {        /* really the MIDI port */
  453.         f = curproc->handle[boutput[3]];
  454.         return file_outstat(f) ? -1 : 0;
  455.     }
  456.     if (dev == 3)
  457.         return BCOSTAT(dev);
  458.  
  459.     if (dev < MAX_BHANDLE) {
  460.         f = curproc->handle[boutput[dev]];
  461.         return file_outstat(f) ? -1 : 0;
  462.     } else
  463.         return bcostat(dev);
  464. }
  465.  
  466. long
  467. bcostat(dev)
  468. int dev;
  469. {
  470.  
  471.     if (dev == CONSDEV) {
  472.         return -1;
  473.     }
  474.     else if (dev == AUXDEV && has_bconmap) {
  475.         dev = curproc->bconmap;
  476.     }
  477. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  478.  * correctly
  479.  */
  480.     else if (dev == 3) dev = 4;
  481.     else if (dev == 4) dev = 3;
  482.  
  483.     return BCOSTAT(dev);
  484. }
  485.  
  486. /* mediach: check for media change */
  487.  
  488. long ARGS_ON_STACK
  489. mediach(dev)
  490. int dev;
  491. {
  492.     long r;
  493.  
  494.     r = callout1(MEDIACH, dev);
  495.     return r;
  496. }
  497.  
  498. /* drvmap: return drives connected to system */
  499.  
  500. long ARGS_ON_STACK
  501. drvmap()
  502. {
  503.     return *( (long *)0x4c2L );
  504. }
  505.  
  506. /* kbshift: return (and possibly change) keyboard shift key status */
  507. /* WARNING: syscall.spp assumes that kbshift never blocks, and never
  508.  * calls any underlying TOS functions
  509.  */
  510. long ARGS_ON_STACK
  511. kbshift(mode)
  512. int mode;
  513. {
  514.     int oldshft;
  515.  
  516.     oldshft = *((unsigned char *)kbshft);
  517.     if (mode >= 0)
  518.         *kbshft = mode;
  519.     return oldshft;
  520. }
  521.  
  522.  
  523. /* special Bconout buffering code:
  524.  * Because system call overhead is so high, programs that do output
  525.  * with Bconout suffer in performance. To compensate for this,
  526.  * Bconout is special-cased in syscall.s, and if possible characters
  527.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  528.  * when any system call other than Bconout happens, or when a context
  529.  * switch occurs.
  530.  */
  531.  
  532. short bconbsiz;            /* number of characters in buffer */
  533. unsigned char bconbuf[256];    /* buffer contents */
  534. short bconbdev;            /* BIOS device for which the buffer is valid */
  535.                 /* (-1 means no buffering is active) */
  536.  
  537. /*
  538.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  539.  * written, non-zero otherwise (just like bconout)
  540.  */
  541.  
  542. long ARGS_ON_STACK
  543. bflush()        /* flush bios output */
  544. {
  545.     long ret, bsiz;
  546.     unsigned char *s;
  547.     FILEPTR *f;
  548.     short dev;
  549.     short statdev;
  550.     long lbconbuf[256];
  551.  
  552.     if ((dev = bconbdev) < 0) return 0;
  553.  
  554. /*
  555.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  556.  * This is necessary because if two or more programs try to do
  557.  * buffered BIOS output at the same time, they can get seriously
  558.  * mixed up. We unlock by setting bconbdev to 0.
  559.  *
  560.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  561.  * order to see if we need to do a bflush; if one is already in
  562.  * progress, it's pointless to do this, so we save a bit of
  563.  * time by setting bconbsiz to 0 here.
  564.  */
  565.     bconbdev = -1;
  566.     bsiz = bconbsiz;
  567.     if (bsiz == 0) return 0;
  568.     bconbsiz = 0;
  569.  
  570. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  571.     if (dev < MAX_BHANDLE || dev == 5) {
  572.         if (dev == 5)
  573.             f = curproc->handle[-1];
  574.         else
  575.             f = curproc->handle[boutput[dev]];
  576.  
  577.         if (!f) {
  578.             bconbdev = 0;
  579.             return 0;
  580.         }
  581.         if (is_terminal(f)) {
  582.             s = bconbuf;
  583.             if (dev == 5) {
  584.                 while (bsiz-- > 0) {
  585.                 if (*s < ' ') {
  586.             /* use ESC-Q to quote control character */
  587.                     (void)tty_putchar(f, (long)'\033',
  588.                                 RAW);
  589.                     (void)tty_putchar(f, (long)'Q',
  590.                                 RAW);
  591.                 }
  592.                 (void) tty_putchar(f, (long)*s++, RAW);
  593.                 }
  594.             } else {
  595. #if 1
  596.                 long *where, nbytes;
  597.  
  598. /* the tty_putchar should set up terminal modes correctly */
  599.                 (void) tty_putchar(f, (long)*s++, RAW);
  600.                 where = lbconbuf;
  601.                 nbytes = 0;
  602.                 while (--bsiz > 0) {
  603.                 *where++ = *s++; nbytes+=4;
  604.                 }
  605.                 if (nbytes)
  606.                 (*f->dev->write)(f, (char *)lbconbuf, nbytes);
  607. #else
  608.                 while (bsiz-- > 0) {
  609.                 (void) tty_putchar(f, (long)*s++, RAW);
  610.                 }
  611. #endif
  612.             }
  613.             ret = -1;
  614.         } else {
  615.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  616.         }
  617.         bconbdev = 0;
  618.         return ret;
  619.     }
  620.  
  621. /* Otherwise, we have a real BIOS device */
  622.  
  623.     if (dev == AUXDEV && has_bconmap) {
  624.         dev = curproc->bconmap;
  625.         statdev = dev;
  626.     }
  627. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  628.     else if (dev == 3) {        /* MIDI */
  629.         statdev = 4;
  630.     } else if (dev == 4) {
  631.         statdev = 3;
  632.     } else
  633.         statdev = dev;
  634.         
  635.     s = bconbuf;
  636.     while (bsiz-- > 0) {
  637.         while (!BCOSTAT(statdev)) yield();
  638.         (void)BCONOUT(dev,*s);
  639.         s++;
  640.     }
  641.     bconbdev = 0;
  642.     return 1L;
  643. }
  644.  
  645. /* initialize bios table */
  646.  
  647. #define BIOS_MAX 0x20
  648.  
  649. Func bios_tab[BIOS_MAX] = {
  650.     getmpb,
  651.     ubconstat,
  652.     ubconin,
  653.     ubconout,
  654.  
  655.     rwabs,
  656.     setexc,
  657.     tickcal,
  658.     getbpb,
  659.  
  660.     ubcostat,
  661.     mediach,
  662.     drvmap,
  663.     kbshift,
  664.  
  665.     0, 0, 0, 0,
  666.     0, 0, 0, 0, 0, 0, 0, 0,
  667.     0, 0, 0, 0, 0, 0, 0, 0
  668. };
  669.  
  670. short bios_max = BIOS_MAX;
  671.  
  672. /*
  673.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  674.  * interrupt routine below
  675.  */
  676.  
  677. void
  678. init_bios()
  679. {
  680.     keyrec = (IOREC_T *)Iorec(1);
  681. }
  682.  
  683. /*
  684.  * do_bconin: try to do a bconin function quickly, without
  685.  * blocking. If we can't do it without blocking, we return
  686.  * 0x0123dead and the calling trap #13 code falls through
  687.  * to the normal bconin stuff. We can't block here because
  688.  * the trap #13 code hasn't yet saved registers or other
  689.  * context bits, so sleep() wouldn't work properly.
  690.  */
  691.  
  692. #define WOULDBLOCK 0x0123deadL
  693.  
  694. /* WARNING: syscall.spp assumes that do_bconin never blocks */
  695.  
  696. long ARGS_ON_STACK
  697. do_bconin(dev)
  698.     int dev;
  699. {
  700.     FILEPTR *f;
  701.     long r;
  702.     unsigned char c;
  703.  
  704.     if (dev < MAX_BHANDLE) {
  705.         f = curproc->handle[binput[dev]];
  706.         if (!f) return 0;
  707.         r = 0;
  708.         (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  709.         if (!r) return WOULDBLOCK;    /* data not ready */
  710.         if (is_terminal(f))
  711.             r = tty_getchar(f, RAW);
  712.         else {
  713.             r = (*f->dev->read)(f, (char *)&c, 1L);
  714.             r = (r == 1) ? c : MiNTEOF;
  715.         }
  716.     } else {
  717.         if (!bconstat(dev))
  718.             r = WOULDBLOCK;
  719.         else
  720.             r = bconin(dev);
  721.     }
  722.     return r;
  723. }
  724.  
  725. /*
  726.  * routine for checking keyboard (called by sleep() on any context
  727.  * switch where a keyboard event occured). returns 1 if a special
  728.  * control character was eaten, 0 if not
  729.  */
  730.  
  731. int
  732. checkkeys()
  733. {
  734.     char scan, ch;
  735.     short shift;
  736.     int sig, ret;
  737.     struct tty *tty = &con_tty;
  738.     extern char mshift;        /* for mouse -- see biosfs.c */
  739.     static short oldktail = 0;
  740.  
  741.     ret = 0;
  742.     mshift = kbshift(-1);
  743.     while (oldktail != keyrec->tail) {
  744.  
  745. /* BUG: we really should check the shift status _at the time the key was
  746.  * pressed_, not now!
  747.  */
  748.         sig = 0;
  749.         shift = mshift;
  750.         oldktail += 4;
  751.         if (oldktail >= keyrec->buflen)
  752.             oldktail = 0;
  753.  
  754.         scan = (keyrec->bufaddr + oldktail)[1];
  755. /* function key?? */
  756.         if ( (scan >= 0x3b && scan <= 0x44) ||
  757.              (scan >= 0x54 && scan <= 0x5d) ||
  758.              scan == DEL || scan == UNDO) {
  759.             if ( (shift & CTRLALT) == CTRLALT ) {
  760.                 oldktail = keyrec->head = keyrec->tail;
  761.                 do_func_key(scan);
  762.                 /* do_func_key may have read some keys */
  763.                 oldktail = keyrec->head;
  764.                 mshift = kbshift (-1);
  765.                 ret = 1;
  766.                 continue;
  767.             }
  768.         }
  769.  
  770. /* check for special control keys, etc. */
  771. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  772.  * ^S/^Q
  773.  */
  774.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  775.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  776.             if (ch == UNDEF)
  777.                 ;    /* do nothing */
  778.             else if (ch == tty->tc.t_intrc)
  779.                 sig = SIGINT;
  780.             else if (ch == tty->tc.t_quitc)
  781.                 sig = SIGQUIT;
  782.             else if (ch == tty->ltc.t_suspc)
  783.                 sig = SIGTSTP;
  784.             else if (ch == tty->tc.t_stopc) {
  785.                 tty->state |= TS_HOLD;
  786.                 ret = 1;
  787.                 keyrec->head = oldktail;
  788.                 continue;
  789.             }
  790.             else if (ch == tty->tc.t_startc) {
  791.                 tty->state &= ~TS_HOLD;
  792.                 ret = 1;
  793.                 keyrec->head = oldktail;
  794.                 continue;
  795.             }
  796.             if (sig) {
  797.                 tty->state &= ~TS_HOLD;
  798.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  799.                     oldktail = keyrec->head = keyrec->tail;
  800.                 killgroup(tty->pgrp, sig);
  801.                 ret = 1;
  802.             }
  803.             else if (tty->state & TS_HOLD) {
  804.                 keyrec->head = oldktail;
  805.                 ret = 1;
  806.             }
  807.         }
  808.  
  809.     }
  810.  
  811. /* has someone done select() on the keyboard?? */
  812.     if (tty->rsel && keyrec->head != keyrec->tail)
  813.         wakeselect(tty->rsel);
  814.  
  815.     return ret;
  816. }
  817.  
  818.  
  819. /*
  820.  * special vector stuff: we try to save as many vectors as possible,
  821.  * just in case we need to restore them later
  822.  *
  823.  * BUG: this really should be integrated with the init_intr routine
  824.  * in main.c
  825.  */
  826.  
  827. #define A(x) ((long *)(long)(x))
  828. #define L(x) (long)(x)
  829.  
  830. struct vectab {
  831.     long *addr;
  832.     long def_value;
  833. } VEC[] = {
  834. {A(0x28), 0},    /* Line A */
  835. {A(0x2c), 0},    /* Line F */
  836. {A(0x60), 0},    /* spurious interrupt */
  837. {A(0x64), 0},      /* level 1 interrupt */
  838. {A(0x68), 0},    /* level 2 interrupt */
  839. {A(0x6c), 0},    /* level 3 interrupt */
  840. {A(0x70), 0},    /* level 4 interrupt */
  841. {A(0x74), 0},    /* level 5 interrupt */
  842. {A(0x78), 0},    /* level 6 interrupt */
  843. {A(0x7c), 0},    /* level 7 interrupt */
  844. {A(0x100), 0},    /* various MFP interrupts */
  845. {A(0x104), 0},
  846. {A(0x108), 0},
  847. {A(0x10c), 0},
  848. {A(0x110), 0},
  849. {A(0x114), 0},
  850. {A(0x118), 0},
  851. {A(0x11c), 0},
  852. {A(0x120), 0},
  853. {A(0x124), 0},
  854. {A(0x128), 0},
  855. {A(0x12c), 0},
  856. {A(0x130), 0},
  857. {A(0x134), 0},
  858. {A(0x138), 0},
  859. {A(0x13c), 0},
  860. {A(0x400), 0},    /* etv_timer */
  861. {A(0x4f6), 0},  /* shell_p */
  862.  
  863. {A(0), 0}    /* special tag indicating end of list */
  864. };
  865.  
  866. void
  867. init_vectors() 
  868. {
  869.     struct vectab *v;
  870.  
  871.     for (v = VEC; v->addr; v++) {
  872.         v->def_value = *(v->addr);
  873.     } 
  874. }
  875.  
  876. #if 0    /* bad code */
  877.  
  878. /* unhook a vector; if possible, do this with XBRA, but
  879.  * if that isn't possible force the vector to have the
  880.  * same value it had when MiNT started
  881.  */
  882.  
  883. static void
  884. unhook(v, where)
  885.     struct vectab *v;
  886.     long where;
  887. {
  888.     xbra_vec *xbra;
  889.     long newval;
  890.     int cookie;
  891.  
  892. /* to check for XBRA, we need access to the memory where the
  893.  * vector is
  894.  */
  895.     cookie = prot_temp(where - 12, 16L, -1);
  896.  
  897.     if (cookie == 0)
  898.         newval = v->def_value;
  899.     else {
  900.         xbra = (xbra_vec *)(where - 12);
  901.         if (xbra->xbra_magic == XBRA_MAGIC) {
  902.             newval = (long)xbra->next;
  903.         } else {
  904.             newval = v->def_value;
  905.         }
  906.     }
  907.     *(v->addr) = newval;
  908.  
  909.     (void)prot_temp(where - 12, 16L, cookie);
  910. }
  911. #endif
  912.  
  913. /*
  914.  * unlink_vectors(start, end): any of the "normal" system vectors
  915.  * pointing into a freed memory region must be reset to their
  916.  * default values, or else we'll get a memory protection violation
  917.  * next time the vector gets called
  918.  */
  919.  
  920. void
  921. unlink_vectors(start, end)
  922.     long start, end;
  923. {
  924. #if 0    /* this code is hosed somewhere */
  925.  
  926.     struct vectab *v;
  927.     long where, *p;
  928.     int i;
  929.  
  930. /* first, unhook any VBL handlers */
  931.     i = *((short *)0x454L);    /* i = nvbls */
  932.     p = *((long **)0x456L);    /* p = _vblqueue */
  933.     while (i-- > 0) {
  934.         where = *p;
  935.         if (where >= start && where < end)
  936.             *p = 0;
  937.         p++;
  938.     }
  939.  
  940. /* next, unhook various random vectors */
  941.     for (v = VEC; v->addr; v++) {
  942.         where = *(v->addr);
  943.         if (where >= start && where < end) {
  944.             unhook(v, where);
  945.         }
  946.     }
  947. #else
  948.     UNUSED(start); UNUSED(end);
  949. #endif
  950. }
  951.  
  952.